﻿using MatFileHandler;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Double;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataWorks_Tools.MatlabDetails
{
    public static class MatlabPredicition
    {
        private static readonly string[] cellNames = new string[]
        {
            "select_input",
            "select_output",
            "train_input",
            "train_output",
            "train_set"
        };
        /// <summary>
        /// 获取单个.mat文件的所有变量信息
        /// </summary>
        /// <param name="matFile"></param>
        /// <returns></returns>
        private static IVariable[] GetOrderVariablesfromMatFile(this string matFile)
        {
            IMatFile matFilecontent;
            using (var fileStream = new System.IO.FileStream(matFile, System.IO.FileMode.Open))
            {
                var reader = new MatFileReader(fileStream);
                matFilecontent = reader.Read();
            }
            return matFilecontent.Variables.OrderBy(a=>a.Name).ToArray();
        }

        /// <summary>
        /// 获取单个.mat文件里的cell类型里的数据，一般为字符串
        /// </summary>
        /// <param name="cellArray"></param>
        /// <returns></returns>
        private static List<string> GetCellArrayStringfromIArray(this IArray array,string name)
        {
            List<string> strings = new List<string>();
            for (int i = 0; i < array.Count; i++)
            {
                //这里分两种情况，第一种为1*n的cell，就是trainset，数据在第二层的cell里，其余的是n*1的cell，数据就在第一层里
                if (name == "train_set")
                {
                    var st = ((ICharArray)((ICellArray)((ICellArray)array).Data[i]).Data[0]).String;
                    strings.Add(st);
                }
                else
                {
                    var st = ((ICharArray)((ICellArray)array).Data[i]).String;
                    strings.Add(st);
                }
            }
            return strings;
        }

        /// <summary>
        /// 从行数和列数和数量num和double数组来创建二维矩阵映射类
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        private static DoubleListtoMatrixMappingModal GetDoubleArrayfromIArray(this IArray array)
        {
            DoubleListtoMatrixMappingModal modal = new DoubleListtoMatrixMappingModal();
            List<double[]> dividedArrays = new List<double[]>();
            var dim = array.Dimensions;
            var list = array.ConvertToDoubleArray();
            //判断是否转换成功
            if (list?.Length > 0)
            {
                if (dim.Length > 1)
                {
                    modal.row = dim[0];
                    modal.column = dim[1];
                    //判断二维矩阵是否有2个以上的数量
                    if (dim.Length > 2)
                    {
                        modal.num = dim[2];
                    }
                    else
                    {
                        modal.num = 1;
                    }
                    var groupSize = array.Count / modal.num;
                    for (int i = 0; i < array.Count; i += groupSize)
                    {
                        double[] group = list.Skip(i).Take(groupSize).ToArray();
                        dividedArrays.Add(group);
                    }
                    modal.lst = dividedArrays;
                }
            }
            else
            {
                modal.success = false;
            }
            return modal;
        }

        /// <summary>
        /// 从二维矩阵映射类来创建二维矩阵数组
        /// </summary>
        /// <param name="modal"></param>
        /// <returns></returns>
        private static List<Matrix<double>> ListToMatrix(this DoubleListtoMatrixMappingModal modal)
        {
            List<Matrix<double>> matrices = new List<Matrix<double>>();
            var MB = Matrix<double>.Build;
            if(modal.success)
            {
                foreach (var lst in modal.lst)
                {
                    var matrix = MB.Dense(modal.row, modal.column, lst);
                    matrices.Add(matrix);
                }
            }
            return matrices;
        }

        /// <summary>
        /// 从二维double数组行向量创建矩阵
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Matrix<double> ArrayRowsToMatrix(this double[][] data)
        {
            var MB = Matrix<double>.Build;
            return MB.DenseOfRows(data);
        }
        /// <summary>
        /// 从二维double数组列向量创建矩阵
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Matrix<double> ArrayColumnsToMatrix(this double[][] data)
        {
            var MB = Matrix<double>.Build;
            return MB.DenseOfColumns(data);
        }


        /// <summary>
        /// 整合上面所有的方法来解析mat文件，最后输出一个统一形式的modal
        /// </summary>
        /// <param name="matFile"></param>
        /// <returns></returns>
        public static List<MatlabFileMappingModal>? TransferMattoUnifiedModal(this string matFile)
        {
            var ivariables = GetOrderVariablesfromMatFile(matFile);
            if(ivariables != null)
            {
                List<MatlabFileMappingModal> modallst= new();
                foreach (var ivar in ivariables)
                {
                    MatlabFileMappingModal modal = new MatlabFileMappingModal();
                    modal.name = ivar.Name;
                    var iarray = ivar.Value;
                    //说明肯定是cell
                    if (cellNames.Contains(modal.name))
                    {
                        var cellstring = GetCellArrayStringfromIArray(iarray, modal.name);
                        modal.celllst = cellstring;
                        modal.iscell = true;

                    }
                    else
                    {
                        var doublemodal=GetDoubleArrayfromIArray(iarray);
                        var matrices = ListToMatrix(doublemodal);
                        modal.matrices = matrices;
                    }
                    modallst.Add(modal);
                }
                return modallst;
            }
            else
            {
                return null;
            }
        }




    }
}
